const request = require('supertest');
const express = require('express');
const portfoliosRoutes = require('../../routes/portfolios');
const mockQuery = jest.fn();
jest.mock('../../config/database', () => ({
  query: (...args) => mockQuery(...args)
}));
jest.mock('../../middleware/auth', () => ({
  authenticateToken: (req, res, next) => { req.user = { id: 1, role: 'user' }; next(); },
  checkRole: () => (req, res, next) => next()
}));

describe('Portfolios Routes', () => {
  let app;
  beforeEach(() => {
    app = express();
    app.use(express.json());
    app.use('/portfolios', portfoliosRoutes);
    mockQuery.mockReset();
  });

  test('GET /portfolios 正常', async () => {
    mockQuery.mockResolvedValueOnce([{ total: 1 }]);
    mockQuery.mockResolvedValueOnce([{ id: 1, name: '组合A' }]);
    const res = await request(app).get('/portfolios');
    expect(res.status).toBe(200);
    expect(res.body.data[0].name).toBe('组合A');
  });

  test('GET /portfolios 500', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).get('/portfolios');
    expect(res.status).toBe(500);
  });

  test('POST /portfolios 正常', async () => {
    mockQuery.mockResolvedValueOnce({ insertId: 1 });
    mockQuery.mockResolvedValue({});
    const res = await request(app).post('/portfolios').send({ name: '新组合', description: '', riskLevel: '', strategyId: 1, fundIds: [1], weights: [1] });
    expect([201, 500]).toContain(res.status);
  });

  test('POST /portfolios 缺少参数', async () => {
    const res = await request(app).post('/portfolios').send({});
    expect([400, 500]).toContain(res.status);
  });

  test('POST /portfolios 500', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).post('/portfolios').send({ name: '新组合', description: '', riskLevel: '', strategyId: 1, fundIds: [1], weights: [1] });
    expect(res.status).toBe(500);
  });

  test('PUT /portfolios/:id/audit 正常', async () => {
    mockQuery.mockResolvedValueOnce(undefined);
    mockQuery.mockResolvedValueOnce(undefined);
    const res = await request(app).put('/portfolios/1/audit').send({ status: 'approved', comment: 'ok' });
    expect([200, 500]).toContain(res.status);
  });

  test('PUT /portfolios/:id/audit 500', async () => {
    mockQuery.mockRejectedValueOnce(new Error('db error'));
    const res = await request(app).put('/portfolios/1/audit').send({ status: 'approved', comment: 'ok' });
    expect(res.status).toBe(500);
  });

  test('GET /portfolios/:id 返回单个组合', async () => {
    mockQuery.mockResolvedValueOnce([{ id: 1, name: '组合A' }]);
    mockQuery.mockResolvedValueOnce([]);
    mockQuery.mockResolvedValueOnce([]);
    mockQuery.mockResolvedValueOnce([]);
    const res = await request(app).get('/portfolios/1');
    expect(res.status).toBe(200);
    expect(res.body.portfolio.id).toBe(1);
  });

  test('GET /portfolios/:id 返回404', async () => {
    mockQuery.mockResolvedValueOnce([]);
    const res = await request(app).get('/portfolios/999');
    expect(res.status).toBe(404);
  });

  test('PUT /portfolios/:id 更新组合', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 1 });
    const res = await request(app).put('/portfolios/1').send({ name: '更新组合' });
    expect([200, 404]).toContain(res.status);
  });

  test('DELETE /portfolios/:id 删除组合', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 1 });
    const res = await request(app).delete('/portfolios/1');
    expect([200, 404]).toContain(res.status);
  });

  test('PUT /portfolios/:id 更新不存在的组合', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 0 });
    const res = await request(app).put('/portfolios/999').send({ name: '不存在' });
    expect(res.status).toBe(404);
  });

  test('DELETE /portfolios/:id 删除不存在的组合', async () => {
    mockQuery.mockResolvedValueOnce({ affectedRows: 0 });
    const res = await request(app).delete('/portfolios/999');
    expect(res.status).toBe(404);
  });
}); 